﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Spk.Db.Data;
using Spk.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using System.Collections;
using AspectCore.Extensions.Reflection;
using Spk.Tools.Hosteviroment;

namespace FirstHomeWork.Utility
{
    public class Excel
    {
        private readonly SpkContext _context;
        private readonly IWebHostEnvironment _hostingEnvironment;
        private static string webRootPath;
        public Excel(SpkContext context, IWebHostEnvironment hostingEnvironment)
        {
            _context = context;
            _hostingEnvironment = hostingEnvironment;
            webRootPath = _hostingEnvironment.ContentRootPath;
        }
        //多线程查询+CSV导出(最大100w条数据)
        /// <summary>
        /// 未做分文件导出(CSV不支持分Sheet)
        /// 未实现不同库查询
        /// 未实现带条件查询
        /// </summary>
        /// <returns></returns>
        public static string ExportByTasks<T>() where T : class
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            var folderPath = webRootPath + "\\Files\\" + string.Format("{0:yyyy_MM}", DateTime.Now) + "\\";
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }
            string newFileName = Guid.NewGuid().ToString() + ".csv";
            var filePath = folderPath + newFileName;
            var txt = new StreamWriter(new FileStream(filePath, FileMode.Create), Encoding.UTF8);
            var thread = 8;
            var times = 10;//分块导入的次数(10次内存占用400m-600m)
            // int count = _context.user.Count() / (thread * times) + 1;
            int count = 1000000 / (thread * times) + 1;
            List<T> resultList = new List<T>(count * thread);
            var j = 0;
            for (int t = 0; t < times; t++)
            {
                var tasks = new Task<List<T>>[thread];
                for (int i = 0; i < thread; i++)
                {
                    tasks[i] = Task.Run(async () =>
                    {
                        Stopwatch sw = new Stopwatch();
                        sw.Restart();
                        int x = Interlocked.Increment(ref j);
                        int i1 = ((x - 1) * count);
                        int i2 = (x * count);
                        using var db = new SpkContext(SpkContext.options);
                        var result = await db.User
                                          .Where(b => b.UserId > i1 && b.UserId <= i2)
                                          .ToListAsync() as List<T>;
                        //Console.WriteLine($"线程{x}:数据为{result.Count()}    查询范围{i1}~{i2}");
                        //Console.WriteLine($"第{t + 1}次多线程查询时间为{sw.ElapsedMilliseconds}");
                        return result;
                    });
                }
                Task.WaitAll(tasks);
                for (int i = 0; i < thread; i++)
                {
                    foreach (var item in tasks[i].Result)
                    {

                        foreach (var child in item.GetType().GetProperties())
                        {
                            txt.Write($"{child.GetValue(item)},");
                        }
                        //var a = GetPropertyReflector(item.GetType());
                        //foreach (var child in a)
                        //{
                        //    txt.Write($"{child.GetValue(item)},");
                        //}
                        txt.WriteLine();
                    }
                    tasks[i].Result.Clear();
                }
                //  Console.WriteLine($"第{t + 1}次导出完毕");
            }
            txt.Dispose();
            Console.WriteLine($"导出成功，总耗时为{stopwatch.ElapsedMilliseconds}");
            return filePath;
        }

        private static readonly Hashtable reflectors = new Hashtable();
        private IEnumerable<PropertyReflector> GetPropertyReflector(Type type)
        {
            IEnumerable<PropertyReflector> result = null;
            if (!reflectors.ContainsKey(type))
            {
                result = type.GetProperties().Select(d => d.GetReflector()).ToArray();
                reflectors.Add(type, result);
            }
            else
            {
                result = (IEnumerable<PropertyReflector>)reflectors[type];
            }

            return result;
        }

        private Task ParallelizeAsync(Func<Task> actionAsync)
        {
#if PARALLELIZE
            const int ParallelizationFactor = 16;
            var tasks = new List<Task>();
            for (var i = 0; i < ParallelizationFactor; i++)
            {
                tasks.Add(Task.Run(() => actionAsync()));
            }

            return Task.WhenAll(tasks);
#else
            return actionAsync();
#endif
        }
    }
}
